Skip to content

feat(accounts): export OpenCode auth json#532

Closed
lNimien wants to merge 4 commits into
Soju06:mainfrom
lNimien:feat/opencode-auth-export
Closed

feat(accounts): export OpenCode auth json#532
lNimien wants to merge 4 commits into
Soju06:mainfrom
lNimien:feat/opencode-auth-export

Conversation

@lNimien

@lNimien lNimien commented May 1, 2026

Copy link
Copy Markdown

Summary

  • Add per-account export for stock OpenCode auth.json payloads.
  • Add dashboard copy/download flow with truncated token previews for long access and refresh tokens.
  • Add backend/frontend coverage plus OpenSpec change artifacts for the new export flow.

Changes

Area Change
Backend Added POST /api/accounts/{account_id}/export/opencode-auth endpoint.
Backend Decrypts stored account tokens and returns stock OpenCode-compatible auth.json.
Backend Derives expires from the access token JWT exp claim in epoch milliseconds.
Backend Adds audit event account_auth_exported without logging token material.
Frontend Adds Export OpenCode auth action to account details.
Frontend Adds export dialog with warning, account metadata, token previews, copy buttons, and download button.
Frontend Keeps downloaded/copied auth.json complete while truncating long tokens visually.
Tests Adds backend integration tests for successful export and missing account.
Tests Adds frontend schema and dialog tests.
OpenSpec Adds add-opencode-auth-export proposal, design, specs, tasks, and verification report.

Test Plan

  • .venv\Scripts\python -m pytest tests/integration/test_account_opencode_auth_export.py tests/unit/test_auth.py -q -ra
    • Result: 6 passed, 1 skipped
    • Skip is expected on Windows for POSIX chmod behavior.
  • bun run test src/features/accounts/schemas.test.ts src/features/accounts/components/opencode-auth-export-dialog.test.tsx
    • Result: 2 files passed, 8 tests passed
  • Manual UI smoke test locally
    • Verified modal does not overflow with long tokens.
    • Verified token previews are truncated.
    • Verified per-token copy buttons.
    • Verified full auth.json copy/download still works.
  • openspec validate --specs
    • Blocked locally because the openspec CLI is not installed/available on PATH.

Notes

  • The exported file intentionally uses stock OpenCode format:
    {
      "openai": {
        "type": "oauth",
        "refresh": "...",
        "access": "...",
        "expires": 1234567890000,
        "accountId": "..."
      }
    }
  • Account email is shown only as dashboard metadata and is not included in the downloaded auth.json.
  • Token values are never logged in the audit event.

Allow users to move a selected account into stock OpenCode without relying on custom multi-account auth fields.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d915f4f4b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

access_token = self._encryptor.decrypt(account.access_token_encrypted)
refresh_token = self._encryptor.decrypt(account.refresh_token_encrypted)
expires = token_expiry_epoch_ms(access_token) or 0
opencode_account_id = account.chatgpt_account_id or account.id

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve null OpenCode accountId when ChatGPT ID is missing

Falling back to account.id here can generate an authJson.openai.accountId value that is not a real ChatGPT account ID (e.g. deduplicated IDs like acc_xxx_<hash> or local fallback IDs). For accounts where chatgpt_account_id is absent, this exports a misleading accountId instead of leaving it unset, and OpenCode will then send that invalid value as ChatGPT-Account-Id, which can cause downstream auth/account selection failures for those exported credentials.

Useful? React with 👍 / 👎.

@Komzpa

Komzpa commented May 16, 2026

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 766d2e0b12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

access_token = self._encryptor.decrypt(account.access_token_encrypted)
refresh_token = self._encryptor.decrypt(account.refresh_token_encrypted)
expires = token_expiry_epoch_ms(access_token) or 0
opencode_account_id = account.chatgpt_account_id or account.id

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep accountId null when ChatGPT account id is unknown

When chatgpt_account_id is missing, this code falls back to account.id and exports that as authJson.openai.accountId. Internal account IDs can be synthetic (for example email_.../local_... or hashed variants), so the export may inject a non-ChatGPT identifier into OpenCode auth and cause downstream requests to send an invalid account header instead of omitting it. The payload should leave accountId unset/null unless a real ChatGPT account id exists.

Useful? React with 👍 / 👎.

@Komzpa Komzpa added 🤖 codex: needs work [@codex review] raised an issue 🤖 codex: ok [@codex review] says no issues found. and removed 🤖 codex: needs work [@codex review] raised an issue 🤖 codex: ok [@codex review] says no issues found. labels May 16, 2026
@Soju06

Soju06 commented May 21, 2026

Copy link
Copy Markdown
Owner

Maintainer cleanup: closing this as stale / no longer merge-ready against the current main.

This PR has been open across substantial main-branch churn and is currently carrying at least one stale signal (conflicts/blocked or failing checks, outstanding codex: needs work, draft/old branch state, or overlap with newer/current implementation). Keeping it open is making the PR queue harder to reason about.

If the change is still needed, please open a fresh, focused PR rebased on current main with green CI and a clean Codex review.

@Soju06 Soju06 closed this May 21, 2026
@Komzpa Komzpa added needs rebase Needs rebase or conflict repair against current main stale No response from reporter; scheduled for close labels May 21, 2026
@Komzpa

Komzpa commented May 21, 2026

Copy link
Copy Markdown
Collaborator

Revived on a maintainer-owned branch as #757 because this PR head has maintainerCanModify=false and cannot be updated here. Keeping credit to the original implementation in the replacement PR.

@Komzpa Komzpa added superseded Replaced by another PR, issue track, or merged implementation and removed 🤖 codex: needs work [@codex review] raised an issue needs rebase Needs rebase or conflict repair against current main labels May 21, 2026
@Soju06 Soju06 added the 🤖 codex: needs work [@codex review] raised an issue label May 21, 2026
@Komzpa Komzpa removed the 🤖 codex: needs work [@codex review] raised an issue label May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale No response from reporter; scheduled for close superseded Replaced by another PR, issue track, or merged implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants